package com.yeskery.nut.http.netty;

import com.yeskery.nut.application.NutApplication;
import com.yeskery.nut.http.BaseResponse;
import com.yeskery.nut.util.IOUtils;
import com.yeskery.nut.util.StringUtils;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;

/**
 * Netty的Http 响应对象
 * @author sprout
 * 2022-05-19 11:28
 */
public class NettyResponse extends BaseResponse {

    private static final int BUFFER_SIZE = 4096;

    /** 通道处理上下文对象 */
    private final ChannelHandlerContext channelHandlerContext;

    /**
     * 构建一个 {@link NettyResponse} 对象
     * @param nutApplication Nut应用对象
     * @param channelHandlerContext 通道处理上下文对象
     */
    public NettyResponse(NutApplication nutApplication, ChannelHandlerContext channelHandlerContext) {
        super(nutApplication);
        this.channelHandlerContext = channelHandlerContext;
    }


    @Override
    protected void writeHeaderBytes(byte[] headers) {
        String headerValue = new String(headers, StandardCharsets.UTF_8);
        String[] headerValues = headerValue.split("\r\n");
        int resultCode = Integer.parseInt(headerValues[0].split(" ")[1]);
        HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(resultCode));
        doWriteHeaderResponse(headerValues, response);
        channelHandlerContext.writeAndFlush(response);
    }

    @Override
    protected void writeBodyBytes(byte[] bytes) {
        channelHandlerContext.writeAndFlush(new DefaultHttpContent(Unpooled.copiedBuffer(bytes)));
    }

    @Override
    protected void writeBodyInputStream(InputStream inputStream) {
        doWriteBodyInputStream(inputStream);
    }

    @Override
    protected void writeBytes(byte[] headers, byte[] bytes) {
        FullHttpResponse response = parseFullHttpResponse(headers, bytes);
        channelHandlerContext.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        output = true;
    }

    @Override
    protected void writeInputStream(byte[] headers, InputStream inputStream) {
        HttpResponse response = parseFullHttpResponse(headers);
        response.headers().add(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
        channelHandlerContext.write(response);

        doWriteBodyInputStream(inputStream);
        channelHandlerContext.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT).addListener(ChannelFutureListener.CLOSE);
        output = true;
    }

    @Override
    public void sendCompleted() {
        super.sendCompleted();
        channelHandlerContext.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT).addListener(ChannelFutureListener.CLOSE);
    }

    /**
     * 执行写入响应体输入流
     * @param inputStream 响应体输入流
     */
    private void doWriteBodyInputStream(InputStream inputStream) {
        IOUtils.transferInputStream(inputStream, BUFFER_SIZE, (bs, i) -> {
            if (i >= BUFFER_SIZE) {
                channelHandlerContext.write(Unpooled.copiedBuffer(bs));
            } else {
                byte[] bytes = new byte[i];
                System.arraycopy(bs, 0, bytes, 0, i);
                channelHandlerContext.writeAndFlush(new DefaultHttpContent(Unpooled.copiedBuffer(bytes)));
            }
        });
    }

    /**
     * 根据请求头字节数据获取响应对象
     * @param headers 请求头字节数据
     * @return 响应对象
     */
    private FullHttpResponse parseFullHttpResponse(byte[] headers) {
        return parseFullHttpResponse(headers, null);
    }

    /**
     * 根据请求头字节数据获取响应对象
     * @param headers 请求头字节数据
     * @param bytes 响应体字节数据
     * @return 响应对象
     */
    private FullHttpResponse parseFullHttpResponse(byte[] headers, byte[] bytes) {
        String headerValue = new String(headers, StandardCharsets.UTF_8);
        String[] headerValues = headerValue.split("\r\n");
        int resultCode = Integer.parseInt(headerValues[0].split(" ")[1]);
        DefaultFullHttpResponse response = bytes == null
                ? new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(resultCode))
                : new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(resultCode), Unpooled.copiedBuffer(bytes));
        doWriteHeaderResponse(headerValues, response);
        return response;
    }

    /**
     * 输出响应头
     * @param headerValues 请求头数组
     * @param response 响应对象
     */
    private void doWriteHeaderResponse(String[] headerValues, HttpResponse response) {
        for (int i = 1; i < headerValues.length; i++) {
            String header = headerValues[i];
            if (!StringUtils.isEmpty(header)) {
                String[] splits = header.split(":");
                if (splits.length == 2) {
                    response.headers().add(splits[0], splits[1]);
                }
            }
        }
    }
}
